﻿using NDK.Motion.Card;
using NDK.Motion.MachineResources;
using NDK.Utils;
using LightController;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Windows.Forms;

namespace NDK.Motion.MachineManager
{
    [Serializable]
    public class MachineDataManager
    {
        public static string ProjectName = string.Empty;
        public static string dirPath = Application.StartupPath + @"\Config\MotionConfig\";
        private static MachineDataManager _instance;
        private static readonly object singletonLock = new object();
        public static MachineDataManager Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (singletonLock)
                    {
                        if (_instance == null)
                        {
                            _instance = new MachineDataManager();
                        }
                    }
                }
                return _instance;
            }
        }
        public List<Axis> AxisList = new List<Axis>();
        public List<InputSetting> DIList = new List<InputSetting>();
        public List<OutputSetting> DOList = new List<OutputSetting>();
        public List<ICylinder> CylinderList = new List<ICylinder>();
        public List<ICard> CardList = new List<ICard>();
        public List<Station> StationList = new List<Station>();
        public List<Position> PositionList = new List<Position>();
        public List<ILightController> LightControllerList = new List<ILightController>();
        public List<Light> LightList = new List<Light>();
        public List<ImageLights> ImageLightsList = new List<ImageLights>();
        public List<ProjectImageLights> ProjectImageLights = new List<ProjectImageLights>();
        public Dictionary<string, DataTable> LocalPostion;


        public OutputSetting SYS_DO_RedLamp = null;
        public OutputSetting SYS_DO_YellowLamp = null;
        public OutputSetting SYS_DO_GreenLamp = null;
        public OutputSetting SYS_DO_Buzzer = null;
        public OutputSetting SYS_DO_AutoManuel = null;
        public InputSetting SYS_DI_Start = null;
        public InputSetting SYS_DI_Pause = null;
        public InputSetting SYS_DI_Reset = null;
        public InputSetting SYS_DI_Emg = null;
        public InputSetting SYS_DI_SafetyScreen = null;
        public InputSetting SYS_DI_SafetyDoor = null;

        public double MotionSpeedPercentage = 100;

        public void Init()
        {
            if (AxisList == null)
                AxisList = new List<Axis>();
            if (DIList == null)
                DIList = new List<InputSetting>();
            if (DOList == null)
                DOList = new List<OutputSetting>();
            if (CylinderList == null)
                CylinderList = new List<ICylinder>();
            if (CardList == null)
                CardList = new List<ICard>();
            if (StationList == null)
                StationList = new List<Station>();
            if (PositionList == null)
                PositionList = new List<Position>();
            else
                PositionSort();
            if (LightControllerList == null)
                LightControllerList = new List<ILightController>();
            if (LightList == null)
                LightList = new List<Light>();
            if (ImageLightsList == null)
                ImageLightsList = new List<ImageLights>();

            if (ProjectImageLights == null)
            {
                ProjectImageLights = new List<ProjectImageLights>();
                ProjectImageLights.Add(new ProjectImageLights("未定义", ImageLightsList));
            }

            UpdateLightList();

            foreach (var light in LightList)
            {
                var lightController = LightControllerList.Find(x => x.Name == light.LightController.Name);
                if (lightController != null)
                    light.LightController = lightController;
            }
            foreach (var project in ProjectImageLights)
            {
                foreach (var image in project.ImageLightsList)
                {
                    foreach (var light in image.LightList)
                    {
                        light.Name = light.LightController.ChanelList[light.LightChanel.No].Name;
                        light.Type = image.ImageName;
                    }
                }
            }

            if (MotionSpeedPercentage == 0)
                MotionSpeedPercentage = 100;
        }

        /// <summary>
        /// 更新光源集合，只保留光源控制器所有通道，其余不保存
        /// </summary>
        public void UpdateLightList()
        {
            LightList.Clear();
            foreach (var lightController in LightControllerList)
            {
                foreach (var channel in lightController.ChanelList)
                {
                    LightList.Add(new Light() { LightController = lightController, Name = channel.Name, LightChanel = new LightChanel() { Name = channel.Name, No = channel.No } });
                }
            }
        }

        private void PositionSort()
        {
            var list = PositionList.GroupBy(x => x.Station)
                .Select(x => new
                {
                    key = x.Key,
                    Value = x.ToList()
                }).ToList();
            PositionList.Clear();
            foreach (var item in list)
            {
                item.Value.Sort((x, y) => x.PositionOrder.CompareTo(y.PositionOrder));
                PositionList.AddRange(item.Value);
            }
        }
        public static void LoadFromFile()
        {
            string path = dirPath + ProjectName + @"\" + ProjectName + ".gra";
            if (File.Exists(path))
            {
                _instance = (MachineDataManager)SerializeUtils.BinaryDeserialize<MachineDataManager>(path);
                _instance.Init();

            }
            else
            {
                Directory.CreateDirectory(dirPath + ProjectName);

            }
        }
        public static void SaveToFile()
        {
            string path = dirPath + ProjectName + @"\" + ProjectName + ".gra";
            SerializeUtils.BinarySerialize<MachineDataManager>(path, Instance);
        }
        #region Card相关操作函数
        /// <summary>
        /// 添加一张卡，卡的名称不能相同
        /// </summary>
        /// <param name="card"></param>
        /// <exception>Card already exists</exception>
        /// <returns>true:添加成功，false:添加失败</returns>
        public bool AddCard(ICard card)
        {
            if (card == null)
            {
                throw new Exception("The card is null！");
            }
            var cardExist = CardList.Find((c) => c.CardName == card.CardName);
            if (cardExist != null)//已经存在该卡，添加失败
            {
                return false;
            }
            try
            {
                CardList.Add(card);
                return true;
            }
            catch (Exception ex)
            {
                throw new Exception("Add card occur exception！" + ex.Message);
            }
        }
        public void RemoveCard(ICard card)
        {
            if (card == null)
            {
                throw new Exception("The card is null！");
            }
            var cardExist = CardList.Find((c) => c.CardName == card.CardName);
            if (cardExist == null)//不存在指定的卡，无需删除失败
            {
                throw new Exception("There is no specified card！");
            }
            try
            {
                CardList.Remove(card);
            }
            catch (Exception ex)
            {
                throw new Exception("Remove card occur exception！" + ex.Message);
            }
        }
        public void RemoveCard(string cardName)
        {
            var cardExist = CardList.Find((c) => c.CardName == cardName);
            if (cardExist == null)//不存在指定的卡，无需删除失败
            {
                throw new Exception("There is no specified card！");
            }
            try
            {
                CardList.Remove(cardExist);
            }
            catch (Exception ex)
            {
                throw new Exception("Remove card[" + cardName + "] occur exception！" + ex.Message);
            }
        }
        public ICard GetCard(string cardName)
        {
            var cardExist = CardList.Find((c) => c.CardName == cardName);
            if (cardExist == null)//不存在指定的卡，无需删除失败
            {
                return null;
            }
            else
            {
                return cardExist;
            }
        }
        public ICard GetCard(ICard card)
        {
            if (card == null)
            {
                throw new Exception("The card is null！");
            }
            var cardExist = CardList.Find((c) => c.CardName == card.CardName);
            if (cardExist == null)//不存在指定的卡，无需删除失败
            {
                return null;
            }
            else
            {
                return cardExist;
            }
        }
        #endregion

        #region Axis相关操作函数
        /// <summary>
        /// 添加一个Axis，卡的名称不能相同
        /// </summary>
        /// <param name="axis"></param>
        /// <exception>Card already exists</exception>
        /// <returns>true:添加成功，false:添加失败</returns>
        public bool AddAxis(Axis axis)
        {
            if (axis == null)
            {
                throw new Exception("The axis is null！");
            }
            var axisExist = AxisList.Find((c) => c.Name == axis.Name && c.Card.CardID == axis.Card.CardID && c.Card.CardID == axis.Card.CardID);
            if (axisExist != null)
            {
                return false;
            }
            try
            {
                AxisList.Add(axis);
                return true;
            }
            catch (Exception ex)
            {
                throw new Exception("Add axis occur exception！" + ex.Message);
            }
        }
        public void RemoveAxis(Axis axis)
        {
            if (axis == null)
            {
                throw new Exception("The axis is null！");
            }
            var axisExist = AxisList.Find((c) => c.Name == axis.Name && c.Card.CardID == axis.Card.CardID && c.Card.CardID == axis.Card.CardID);
            if (axisExist == null)//不存在指定的卡，无需删除失败
            {
                throw new Exception("There is no specified axis！");
            }
            try
            {
                AxisList.Remove(axis);
            }
            catch (Exception ex)
            {
                throw new Exception("Remove axis occur exception！" + ex.Message);
            }
        }
        public void RemoveAxis(string axisName)
        {
            var axisExist = AxisList.Find((c) => c.Name == axisName);
            if (axisExist == null)
            {
                throw new Exception("There is no specified axis！");
            }
            try
            {
                AxisList.Remove(axisExist);
            }
            catch (Exception ex)
            {
                throw new Exception("Remove axis[" + axisName + "] occur exception！" + ex.Message);
            }
        }
        public Axis GetAxis(string axisName)
        {
            var axisExist = AxisList.Find((c) => c.Name == axisName);
            if (axisExist == null)
            {
                return null;
            }
            else
            {
                return axisExist;
            }
        }
        public Axis GetAxis(Axis axis)
        {
            if (axis == null)
            {
                throw new Exception("The axis is null！");
            }
            var axisExist = AxisList.Find((c) => c.Name == axis.Name && c.Card.CardID == axis.Card.CardID && c.Card.CardID == axis.Card.CardID);
            if (axisExist == null)
            {
                return null;
            }
            else
            {
                return axisExist;
            }
        }
        #endregion

        #region DO相关操作函数
        /// <summary>
        /// 添加一个DO，名称不能相同
        /// </summary>
        /// <param name="outputModel"></param>
        /// <returns>true:添加成功，false:添加失败</returns>
        public bool AddDO(OutputSetting outputModel)
        {
            if (outputModel == null)
            {
                throw new Exception("The DO is null！");
            }
            var outputModelExist = DOList.Find((c) => c.Name == outputModel.Name && c.Card.CardType == outputModel.Card.CardType);
            if (outputModelExist != null)
            {
                return false;
            }
            try
            {
                DOList.Add(outputModel);
                return true;
            }
            catch (Exception ex)
            {
                throw new Exception("Add DO occur exception！" + ex.Message);
            }
        }
        public void RemoveDO(OutputSetting outputModel)
        {
            if (outputModel == null)
            {
                throw new Exception("The DO is null！");
            }
            var axisExist = DOList.Find((c) => c.Name == outputModel.Name && c.Card.CardType == outputModel.Card.CardType);
            if (axisExist == null)
            {
                throw new Exception("There is no specified DO！");
            }
            try
            {
                DOList.Remove(outputModel);
            }
            catch (Exception ex)
            {
                throw new Exception("Remove DO occur exception！" + ex.Message);
            }
        }
        public void RemoveDO(string name)
        {
            var outputExist = DOList.Find((c) => c.Name == name);
            if (outputExist == null)//不存在指定的卡，无需删除失败
            {
                throw new Exception("There is no specified DO！");
            }
            try
            {
                DOList.Remove(outputExist);
            }
            catch (Exception ex)
            {
                throw new Exception("Remove DO [" + name + "] occur exception！" + ex.Message);
            }
        }
        public OutputSetting GetDO(string name)
        {
            var outputExist = DOList.Find((c) => c.Name == name);
            if (outputExist == null)
            {
                return null;
            }
            else
            {
                return outputExist;
            }
        }
        public OutputSetting GetDO(OutputSetting outputModel)
        {
            if (outputModel == null)
            {
                throw new Exception("The DO is null！");
            }
            var outputExist = DOList.Find((c) => c.Name == outputModel.Name && c.Card.CardType == outputModel.Card.CardType);
            if (outputExist == null)//不存在指定的轴，返回空
            {
                return null;
            }
            else
            {
                return outputExist;
            }
        }
        #endregion

        #region DI相关操作函数
        /// <summary>
        /// 添加一个DI，名称不能相同
        /// </summary>
        /// <param name="InputSetting"></param>
        /// <returns>true:添加成功，false:添加失败</returns>
        public bool AddDI(InputSetting InputSetting)
        {
            if (InputSetting == null)
            {
                throw new Exception("The DI is null！");
            }
            var outputModelExist = DIList.Find((c) => c.Name == InputSetting.Name && c.Card.CardType == InputSetting.Card.CardType);
            if (outputModelExist != null)
            {
                return false;
            }
            try
            {
                DIList.Add(InputSetting);
                return true;
            }
            catch (Exception ex)
            {
                throw new Exception("Add DI occur exception！" + ex.Message);
            }
        }
        public void RemoveDI(InputSetting InputSetting)
        {
            if (InputSetting == null)
            {
                throw new Exception("The DI is null！");
            }
            var inputExist = DIList.Find((c) => c.Name == InputSetting.Name && c.Card.CardType == InputSetting.Card.CardType);
            if (inputExist == null)
            {
                throw new Exception("There is no specified DI！");
            }
            try
            {
                DIList.Remove(InputSetting);
            }
            catch (Exception ex)
            {
                throw new Exception("Remove DI occur exception！" + ex.Message);
            }
        }
        public void RemoveDI(string name)
        {
            var outputExist = DIList.Find((c) => c.Name == name);
            if (outputExist == null)
            {
                throw new Exception("There is no specified DI！");
            }
            try
            {
                DIList.Remove(outputExist);
            }
            catch (Exception ex)
            {
                throw new Exception("Remove DI [" + name + "] occur exception！" + ex.Message);
            }
        }
        public InputSetting GetDI(string name)
        {
            var outputExist = DIList.Find((c) => c.Name == name);
            if (outputExist == null)
            {
                return null;
            }
            else
            {
                return outputExist;
            }
        }
        public InputSetting GetDI(InputSetting InputSetting)
        {
            if (InputSetting == null)
            {
                throw new Exception("The DI is null！");
            }
            var outputExist = DIList.Find((c) => c.Name == InputSetting.Name && c.Card.CardType == InputSetting.Card.CardType);
            if (outputExist == null)//不存在指定的轴，返回空
            {
                return null;
            }
            else
            {
                return outputExist;
            }
        }

        /// <summary>
        /// 清空运动控制相关的文件
        /// </summary>
        public void ClearFile()
        {
            string dir = dirPath + ProjectName;
            try
            {
                if (!Directory.Exists(dir))
                {
                    Directory.CreateDirectory(dir);
                }
                else
                {
                    var files = FileUtils.GetFileNames(dir);
                    foreach (var file in files)
                    {
                        string temp = file.ToLower();//统一转换为小写
                        if (temp.EndsWith(".csv") || temp.EndsWith(".gra"))
                        {
                            File.Delete(file);
                        }
                    }
                }
            }
            catch { }
        }



        static string dirPath_PositionTable = dirPath;

        public bool IsExistPositionTable(string station)
        {
            string dirPath = dirPath_PositionTable + ProjectName;
            string filePath = dirPath + @"\" + station + @".csv";
            if (File.Exists(filePath))
            {
                return true;
            }
            return false;
        }
        public void DeletePositionTable(string station)
        {
            string dirPath = dirPath_PositionTable + ProjectName;
            string filePath = dirPath + @"\" + station + @".csv";
            if (File.Exists(filePath)) File.Delete(filePath);
        }
        /// <summary>
        /// 保存点位到本地配置文件，CSV和二进制文件
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="station"></param>
        public void SavePositionTable(DataTable dt, string station)
        {
            string dirPath = dirPath_PositionTable + ProjectName;
            string filePath = dirPath + @"\" + station + @".csv";
            if (!Directory.Exists(dirPath))
            {
                Directory.CreateDirectory(dirPath);
            }
            try
            {
                FileUtils.SaveCSV(dt, filePath);

                SaveToFile();
            }
            catch (Exception ex)
            {

            }
        }
        /// <summary>
        /// 加载本地csv点位文件到Datatable
        /// </summary>
        /// <param name="station"></param>
        /// <returns></returns>
        public DataTable LoadPositionTable(string station)
        {
            string dirPath = dirPath_PositionTable + ProjectName;
            string filePath = dirPath + @"\" + station + @".csv";
            if (!Directory.Exists(dirPath))
            {
                Directory.CreateDirectory(dirPath);
            }
            try
            {
                DataTable dt = FileUtils.OpenCSV(filePath);
                return dt;
            }
            catch { }
            return null;
        }
        #endregion
    }
}
